package com.tian.netty.core;


import com.alibaba.fastjson.JSON;
import com.tian.dto.ChargeStationGunStatusInfo;
import com.tian.enums.ChargerGunStatusEnum;
import com.tian.message.MessageReqIdPrefixConstant;
import com.tian.message.StationGunCommunicateLogMessage;
import com.tian.producer.StationGunCommunicateLogProducer;
import com.tian.util.DateUtils;
import com.tian.util.JConverter;
import com.tian.util.Utility;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.UUID;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * 2023年11月05日 22:59
 * 在线刷题 1200+题和1000+篇干货文章：<a href="https://woaijava.cc/">博客地址</a>
 * <p>
 *  用于处理从客户端接收到的消息
 */
@Slf4j
public class MsgInBoundHandler extends SimpleChannelInboundHandler<byte[]> {
    
    private static final Logger logger = LoggerFactory.getLogger(MsgInBoundHandler.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] msgObject) throws Exception {
        //接收到的客户端消息
        logger.info("C(" + (ctx.channel().remoteAddress()) + " ==>>S:" + JConverter.bytes2String(msgObject));
        ReqDispatcher.submit((SocketChannel)ctx.channel(), msgObject);
    }
    
    /*
     * 在channel被启用的时候触发 (在建立连接的时候)
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {  
        logger.info("Client : " + ctx.channel().remoteAddress() + " active !");
    }
    
    /*
     * 在channel断开的时候触发 
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("Client : " + ctx.channel().remoteAddress() + " inactive !");
        //连接关闭后，清理系统资源
        String chargerNo = ClientChannelMap.getChargerNo(ctx.channel().id().asLongText());
        if (chargerNo != null && !"".equals(chargerNo.trim())) {
            //移除客户端连接
            ClientChannelMap.remove(chargerNo);
            //更新电桩状态为离线状态
            RedissonClient redissonClient = Utility.getBean(RedissonClient.class);
            RBucket<String> chargerOnlineBucket = redissonClient.getBucket("charger.online_" + chargerNo);
            ChargeStationGunStatusInfo chargeStationGunStatusInfo = JSON.parseObject(chargerOnlineBucket.get(), ChargeStationGunStatusInfo.class);
            chargeStationGunStatusInfo.setGunStatus(ChargerGunStatusEnum.OFFLINE.getChargerStatus());
            chargerOnlineBucket.set(JSON.toJSONString(chargeStationGunStatusInfo));

            log.info("充电桩下线，充电桩编号：{}", chargerNo);
            //存储离线日志
            StationGunCommunicateLogProducer stationGunCommunicateLogProducer = Utility.getBean(StationGunCommunicateLogProducer.class);
            StationGunCommunicateLogMessage stationGunCommunicateLogMessage = new StationGunCommunicateLogMessage();
            stationGunCommunicateLogMessage.setGunNo(chargerNo);
            stationGunCommunicateLogMessage.setLogType(com.tian.enums.LogType.OFFLINE.getType());
            stationGunCommunicateLogMessage.setLogTime(LocalDateTime.now());
            stationGunCommunicateLogMessage.setReqId(MessageReqIdPrefixConstant.CHARGE_STATION_GUN_REQ_ID_PREFIX
                    + UUID.randomUUID() + DateUtils.formatDefaultDateMs());
            stationGunCommunicateLogProducer.send(stationGunCommunicateLogMessage);
        }
    }
    
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    }

    /*
     * 异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("channel is exception over.(SocketChannel)ctx.channel()=" + (SocketChannel)ctx.channel(), cause);
    } 
}
